import * as CANNON from "cannon-es";
import CannonDebugger from "cannon-es-debugger";

export default class ThreeJsPhysicsWorld {
  constructor(threeJsWorld) {
    this.threeJsWorld = threeJsWorld;
    this.world = null;
    this.groundMaterial = null;
    this.materials = {};
  }
  initWorld() {
    this.registePhysicsMaterial("default", new CANNON.Material());
    this.createWorld();
    this.createGround();
    this.registePhysicsMaterial("groundMaterial", this.groundMaterial);
    this.addContactMaterial(
      new CANNON.ContactMaterial(this.groundMaterial, this.materials.default, {
        restitution: 0.9, //反弹恢复系数
      })
    );
  }
  createWorld() {
    this.world = new CANNON.World();
    // 设置物理世界重力加速度
    this.world.gravity.set(0, -9.8, 0);
  }
  createGround() {
    // 物理地面
    this.groundMaterial = new CANNON.Material();
    const groundBody = new CANNON.Body({
      mass: 0, // 质量为0，始终保持静止，不会受到力碰撞或加速度影响
      shape: new CANNON.Plane(),
      material: this.groundMaterial,
    });
    // 改变平面默认的方向，法线默认沿着z轴，旋转到平面向上朝着y方向
    groundBody.quaternion.setFromEuler(-Math.PI / 2, 0, 0); //旋转规律类似threejs 平面
    this.world.addBody(groundBody);
  }
  addContactMaterial(contactMaterial) {
    this.world.addContactMaterial(contactMaterial);
  }
  registePhysicsMaterial(name, physicsMaterial) {
    this.materials[name] = physicsMaterial;
  }
  addSphere(sphere) {
    const body = new CANNON.Body({
      mass: 1, //碰撞体质量
      material: this.materials.default, //碰撞体材质
      shape: new CANNON.Sphere(sphere.geometry.parameters.radius),
      position: sphere.position,
    });
    this.world.addBody(body);
    return this.threeJsWorld.addObj(sphere, body);
  }
  addBox(box, mass, eternalLife) {
    const boxParams = box.geometry.parameters;
    const boxVec3 = new CANNON.Vec3(
      boxParams.width / 2,
      boxParams.height / 2,
      boxParams.depth / 2
    );
    if (!mass && mass != 0) {
      mass = 1;
    }
    // 物理立方体
    const boxBody = new CANNON.Body({
      mass: mass, //碰撞体质量
      material: this.materials.default, //碰撞体材质
      shape: new CANNON.Box(boxVec3),
      position: box.position,
      quaternion: box.quaternion,
    });
    this.world.addBody(boxBody);
    if (!eternalLife) {
      return this.threeJsWorld.addObj(box, boxBody);
    }
    return { obj: box, objBody: boxBody };
  }
  startWorld() {
    const cannonDebugger = new CannonDebugger(
      this.threeJsWorld.scene,
      this.world
    );
    this.threeJsWorld.registeUpdateFun(() => {
      this.world.step(1 / 60); //更新物理计算
      cannonDebugger.update();
    });
  }
  removeObj(obj) {
    this.world.removeBody(obj);
  }
}
